/*
 * Translated from the Koprina project, a Java implementation of the Skype SILK codec
 * http://code.google.com/p/koprina/
 */

using System;

namespace SilkSharp
{
	public class Silk_SigProc_FIX_constants
	{
		/*
		 * max order of the LPC analysis in schur() and k2a().
		 */
		public const int SKP_Silk_MAX_ORDER_LPC = 16; /* max order of the LPC analysis in schur() and k2a()    */
		/*
		 * max input length to the correlation.
		 */
		public const int SKP_Silk_MAX_CORRELATION_LENGTH = 640;/* max input length to the correlation                   */

		/* Pitch estimator */
		public const int SKP_Silk_PITCH_EST_MIN_COMPLEX = 0;
		public const int SKP_Silk_PITCH_EST_MID_COMPLEX = 1;
		public const int SKP_Silk_PITCH_EST_MAX_COMPLEX = 2;

		/* parameter defining the size and accuracy of the piecewise linear  */
		/* cosine approximatin table.                                        */
		public const int LSF_COS_TAB_SZ_FIX = 128;
		/* rom table with cosine values */
		//	(to see rom table value, refer to Silk_LSF_cos_table.java)
	}

	public class Silk_SigProc_FIX : Silk_SigProc_FIX_constants
	{
		/*
		 * Rotate a32 right by 'rot' bits. Negative rot values result in rotating
		 * left. Output is 32bit int.
		 * 
		 * @param a32
		 * @param rot
		 * @return
		 */
		public static int SKP_ROR32( int a32, int rot )
		{
			if( rot <= 0 )
				return ( ( a32 << -rot ) | Silk_macros.TRIPLE_SHIFT( a32, 32 + rot ) ); //(a32 >>> (32 + rot)));
			else
				return ( ( a32 << ( 32 - rot ) ) | Silk_macros.TRIPLE_SHIFT( a32, rot ) ); //(a32 >>> rot));
		}

		/* fixed point */

		/*
		 * (a32 * b32) output have to be 32bit int
		 */
		public static int SKP_MUL( int a32, int b32 )
		{
			return a32 * b32;
		}

		/*
		 * (a32 * b32) output have to be 32bit uint.
		 * @param a32
		 * @param b32
		 * @return
		 */
		public static long SKP_MUL_uint( long a32, long b32 )
		{
			return a32 * b32;
		}

		/*
		 *  a32 + (b32 * c32) output have to be 32bit int
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_MLA( int a32, int b32, int c32 )
		{
			return a32 + b32 * c32;
		}

		/*
		 *  a32 + (b32 * c32) output have to be 32bit uint
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static long SKP_MLA_uint( long a32, long b32, long c32 )
		{
			return a32 + b32 * c32;
		}

		/*
		 * ((a32 >> 16)  * (b32 >> 16)) output have to be 32bit int
		 * @param a32
		 * @param b32
		 * @return
		 */
		public static int SKP_SMULTT( int a32, int b32 )
		{
			return ( ( ( a32 ) >> 16 ) * ( ( b32 ) >> 16 ) );
		}

		/*
		 *  a32 + ((b32 >> 16)  * (c32 >> 16)) output have to be 32bit int
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLATT( int a32, int b32, int c32 )
		{
			return ( a32 ) + ( ( b32 ) >> 16 ) * ( ( c32 ) >> 16 );
		}

		/*
		 * SKP_ADD64((a64),(SKP_int64)((SKP_int32)(b16) * (SKP_int32)(c16))).
		 * @param a64
		 * @param b16
		 * @param c16
		 * @return
		 */
		public static long SKP_SMLALBB( long a64, short b16, short c16 )
		{
			return ( a64 ) + (long)( (int)( b16 ) * (int)( c16 ) );
		}

		/*
		 * (a32 * b32)
		 * @param a32
		 * @param b32
		 * @return
		 */
		public static long SKP_SMULL( int a32, int b32 )
		{
			return ( (long)( a32 ) * /*(long)*/( b32 ) );
		}

		// multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)
		/*
		 * SKP_MLA(a32, b32, c32).
		 */
		public static int SKP_MLA_ovflw( int a32, int b32, int c32 )
		{
			return a32 + b32 * c32;
		}

		/*
		 * SKP_SMLABB(a32, b32, c32)
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLABB_ovflw( int a32, int b32, int c32 )
		{
			return ( ( a32 ) + ( (int)( (short)( b32 ) ) ) * (int)( (short)( c32 ) ) );
		}
		/*
		 * SKP_SMLABT(a32, b32, c32)
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLABT_ovflw( int a32, int b32, int c32 )
		{
			return ( ( a32 ) + ( (int)( (short)( b32 ) ) ) * ( ( c32 ) >> 16 ) );
		}
		/*
		 * SKP_SMLATT(a32, b32, c32)
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLATT_ovflw( int a32, int b32, int c32 )
		{
			return ( a32 ) + ( ( b32 ) >> 16 ) * ( ( c32 ) >> 16 );
		}
		/*
		 * SKP_SMLAWB(a32, b32, c32)
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLAWB_ovflw( int a32, int b32, int c32 )
		{
			return ( ( a32 ) + ( ( ( ( b32 ) >> 16 ) * (int)( (short)( c32 ) ) ) + ( ( ( ( b32 ) & 0x0000FFFF ) * (int)( (short)( c32 ) ) ) >> 16 ) ) );
		}
		/*
		 * SKP_SMLAWT(a32, b32, c32)
		 * @param a32
		 * @param b32
		 * @param c32
		 * @return
		 */
		public static int SKP_SMLAWT_ovflw( int a32, int b32, int c32 )
		{
			return ( ( a32 ) + ( ( ( b32 ) >> 16 ) * ( ( c32 ) >> 16 ) ) + ( ( ( ( b32 ) & 0x0000FFFF ) * ( ( c32 ) >> 16 ) ) >> 16 ) );
		}

		/*
		 * ((a64)/(b32))
		 * TODO: rewrite it as a set of SKP_DIV32.
		 */
		public static long SKP_DIV64_32( long a64, int b32 )
		{
			return a64 / b32;
		}

		/*
		 * ((int)((a32) / (b16)))
		 * @param a32
		 * @param b16
		 * @return
		 */
		public static int SKP_DIV32_16( int a32, short b16 )
		{
			return ( (int)( ( a32 ) / ( b16 ) ) );
		}
		/*
		 * ((SKP_int32)((a32) / (b32)))
		 * @param a32
		 * @param b32
		 * @return
		 */
		public static int SKP_DIV32( int a32, int b32 )
		{
			return ( (int)( ( a32 ) / ( b32 ) ) );
		}

		// These macros enables checking for overflow in SKP_Silk_API_Debug.h
		/*
		 * ((a) + (b))
		 */
		public static short SKP_ADD16( short a, short b )
		{
			return (short)( a + b );
		}
		/*
		 * ((a) + (b))
		 * @param a
		 * @param b
		 * @return
		 */
		public static int SKP_ADD32( int a, int b )
		{
			return a + b;
		}
		/*
		 * ((a) + (b))
		 * @param a
		 * @param b
		 * @return
		 */
		public static long SKP_ADD64( long a, long b )
		{
			return a + b;
		}

		/*
		 * ((a) - (b))
		 * @param a
		 * @param b
		 * @return
		 */
		public static short SKP_SUB16( short a, short b )
		{
			return (short)( a - b );
		}
		/*
		 * ((a) - (b))
		 * @param a
		 * @param b
		 * @return
		 */
		public static int SKP_SUB32( int a, int b )
		{
			return a - b;
		}
		/*
		 * ((a) - (b))
		 * @param a
		 * @param b
		 * @return
		 */
		public static long SKP_SUB64( long a, long b )
		{
			return a - b;
		}

		public static int SKP_SAT8( int a )
		{
			return ( ( a ) > Byte.MaxValue ? Byte.MaxValue : ( ( a ) < Byte.MinValue ? Byte.MinValue : ( a ) ) );
		}

		public static int SKP_SAT16( int a )
		{
			return ( ( a ) > short.MaxValue ? short.MaxValue : ( ( a ) < short.MinValue ? short.MinValue : ( a ) ) );
		}

		public static long SKP_SAT32( long a )
		{
			return ( ( a ) > int.MaxValue ? int.MaxValue : ( ( a ) < int.MinValue ? int.MinValue : ( a ) ) );
		}

		/*
		 * (a)
		 * @param a
		 * @return
		 */
		public static byte SKP_CHECK_FIT8( int a )
		{
			return (byte)a;
		}
		/*
		 * (a)
		 * @param a
		 * @return
		 */
		public static short SKP_CHECK_FIT16( int a )
		{
			return (short)a;
		}
		/*
		 * (a)
		 * @param a
		 * @return
		 */
		public static int SKP_CHECK_FIT32( int a )
		{
			return a;
		}

		public static short SKP_ADD_SAT16( short a, short b )
		{
			return (short)SKP_SAT16( (int)( a ) + ( b ) );
		}

		public static long SKP_ADD_SAT64( long a, long b )
		{
			if( ( (ulong)( a + b ) & 0x8000000000000000L ) == 0 )
				return ( (ulong)( a & b ) & 0x8000000000000000L ) != 0 ? long.MinValue : a + b;
			else
				return ( (ulong)( a | b ) & 0x8000000000000000L ) == 0 ? long.MaxValue : a + b;
		}

		public static short SKP_SUB_SAT16( short a, short b )
		{
			return (short)SKP_SAT16( (int)( a ) - ( b ) );
		}

		public static long SKP_SUB_SAT64( long a, long b )
		{
			if( ( (ulong)( a - b ) & 0x8000000000000000L ) == 0 )
				return ( (ulong)a & ( (ulong)b ^ 0x8000000000000000L ) & 0x8000000000000000L ) != 0 ? long.MinValue : a - b;
			else
				return ( ( (ulong)a ^ 0x8000000000000000L ) & (ulong)b & 0x8000000000000000L ) != 0 ? long.MaxValue : a - b;
		}

		/* Saturation for positive input values */
		public static long SKP_POS_SAT32( long a )
		{
			return ( ( a ) > int.MaxValue ? int.MaxValue : ( a ) );
		}

		/* Add with saturation for positive input values */
		public static byte SKP_ADD_POS_SAT8( byte a, byte b )
		{
			return ( ( a + b ) & 0x80 ) != 0 ? Byte.MaxValue : (byte)( a + b );
		}
		public static short SKP_ADD_POS_SAT16( short a, short b )
		{
			return ( ( a + b ) & 0x8000 ) != 0 ? short.MaxValue : (short)( a + b );
		}
		public static int SKP_ADD_POS_SAT32( int a, int b )
		{
			return ( ( ( ( a ) + ( b ) ) & 0x80000000 ) != 0 ? int.MaxValue : ( ( a ) + ( b ) ) );
		}
		public static long SKP_ADD_POS_SAT64( long a, long b )
		{
			return ( ( (ulong)( ( a ) + ( b ) ) & 0x8000000000000000L ) != 0 ? long.MaxValue : ( ( a ) + ( b ) ) );
		}

		/*
		 * ((a)<<(shift))                // shift >= 0, shift < 8
		 * @param a
		 * @param shift
		 * @return
		 */
		public static byte SKP_LSHIFT8( byte a, int shift )
		{
			return (byte)( a << shift );
		}
		/*
		 * ((a)<<(shift))                // shift >= 0, shift < 16
		 * @param a
		 * @param shift
		 * @return
		 */
		public static short SKP_LSHIFT16( short a, int shift )
		{
			return (short)( a << shift );
		}
		/*
		 * ((a)<<(shift))                // shift >= 0, shift < 32
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_LSHIFT32( int a, int shift )
		{
			return a << shift;
		}
		/*
		 * ((a)<<(shift))                // shift >= 0, shift < 64
		 * @param a
		 * @param shift
		 * @return
		 */
		public static long SKP_LSHIFT64( long a, int shift )
		{
			return a << shift;
		}
		/*
		 * (a, shift)               SKP_LSHIFT32(a, shift)        // shift >= 0, shift < 32
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_LSHIFT( int a, int shift )
		{
			return a << shift;
		}

		/*
		 * ((a)>>(shift))                // shift >= 0, shift < 8
		 * @param a
		 * @param shift
		 * @return
		 */
		public static byte SKP_RSHIFT8( byte a, int shift )
		{
			return (byte)( a >> shift );
		}
		/*
		 * ((a)>>(shift))                // shift >= 0, shift < 16
		 * @param a
		 * @param shift
		 * @return
		 */
		public static short SKP_RSHIFT16( short a, int shift )
		{
			return (short)( a >> shift );
		}
		/*
		 * ((a)>>(shift))                // shift >= 0, shift < 32
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_RSHIFT32( int a, int shift )
		{
			return a >> shift;
		}
		/*
		 * ((a)>>(shift))                // shift >= 0, shift < 64
		 * @param a
		 * @param shift
		 * @return
		 */
		public static long SKP_RSHIFT64( long a, int shift )
		{
			return a >> shift;
		}
		/*
		 * SKP_RSHIFT32(a, shift)        // shift >= 0, shift < 32
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_RSHIFT( int a, int shift )
		{
			return a >> shift;
		}

		/* saturates before shifting */
		public static short SKP_LSHIFT_SAT16( short a, int shift )
		{
			return SKP_LSHIFT16( SKP_LIMIT_16( a, (short)( short.MinValue >> shift ), (short)( short.MaxValue >> shift ) ), shift );
		}

		public static int SKP_LSHIFT_SAT32( int a, int shift )
		{
			return SKP_LSHIFT32( SKP_LIMIT( a, int.MinValue >> shift, int.MaxValue >> shift ), shift );
		}

		/*
		 * ((a)<<(shift))        // shift >= 0, allowed to overflow
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_LSHIFT_ovflw( int a, int shift )
		{
			return a << shift;
		}
		/*
		 * ((a)<<(shift))        // shift >= 0
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_LSHIFT_uint( int a, int shift )
		{
			return a << shift;
		}
		/*
		 * ((a)>>(shift))        // shift >= 0
		 * @param a
		 * @param shift
		 * @return
		 */
		public static int SKP_RSHIFT_uint( int a, int shift )
		{
			return Silk_macros.TRIPLE_SHIFT( a, shift );
		}

		/*
		 * ((a) + SKP_LSHIFT((b), (shift)))            // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_LSHIFT( int a, int b, int shift )
		{
			return a + ( b << shift );
		}
		/*
		 * SKP_ADD32((a), SKP_LSHIFT32((b), (shift)))    // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_LSHIFT32( int a, int b, int shift )
		{
			return a + ( b << shift );
		}
		/*
		 * ((a) + SKP_LSHIFT_uint((b), (shift)))        // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_LSHIFT_uint( int a, int b, int shift )
		{
			return a + ( b << shift );
		}
		/*
		 * ((a) + SKP_RSHIFT((b), (shift)))            // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_RSHIFT( int a, int b, int shift )
		{
			return a + ( b >> shift );
		}
		/*
		 * SKP_ADD32((a), SKP_RSHIFT32((b), (shift)))    // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_RSHIFT32( int a, int b, int shift )
		{
			return a + ( b >> shift );
		}
		/*
		 * ((a) + SKP_RSHIFT_uint((b), (shift)))        // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_ADD_RSHIFT_uint( int a, int b, int shift )
		{
			return a + Silk_macros.TRIPLE_SHIFT( b, shift );
		}
		/*
		 * SKP_SUB32((a), SKP_LSHIFT32((b), (shift)))    // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_SUB_LSHIFT32( int a, int b, int shift )
		{
			return a - ( b << shift );
		}
		/*
		 * SKP_SUB32((a), SKP_RSHIFT32((b), (shift)))    // shift >= 0
		 * @param a
		 * @param b
		 * @param shift
		 * @return
		 */
		public static int SKP_SUB_RSHIFT32( int a, int b, int shift )
		{
			return a - ( b >> shift );
		}

		/* Requires that shift > 0 */
		/*
		 * ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
		 */
		public static int SKP_RSHIFT_ROUND( int a, int shift )
		{
			return shift == 1 ? ( a >> 1 ) + ( a & 1 ) : ( ( a >> ( shift - 1 ) ) + 1 ) >> 1;
		}
		/*
		 * ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
		 * @param a
		 * @param shift
		 * @return
		 */
		public static long SKP_RSHIFT_ROUND64( long a, int shift )
		{
			return shift == 1 ? ( a >> 1 ) + ( a & 1 ) : ( ( a >> ( shift - 1 ) ) + 1 ) >> 1;
		}

		/* Number of rightshift required to fit the multiplication */
		public static int SKP_NSHIFT_MUL_32_32( int a, int b )
		{
			return -( 31 - ( 32 - Silk_macros.SKP_Silk_CLZ32( Math.Abs( a ) ) + ( 32 - Silk_macros.SKP_Silk_CLZ32( Math.Abs( b ) ) ) ) );
		}
		public static int SKP_NSHIFT_MUL_16_16( short a, short b )
		{
			return -( 15 - ( 16 - Silk_macros.SKP_Silk_CLZ16( (short)Math.Abs( a ) ) + ( 16 - Silk_macros.SKP_Silk_CLZ16( (short)Math.Abs( b ) ) ) ) );
		}


		public static int SKP_min( int a, int b )
		{
			return a < b ? a : b;
		}
		public static int SKP_max( int a, int b )
		{
			return a > b ? a : b;
		}

		/* Macro to convert floating-point constants to fixed-point */
		/*
		 * ((int)((C) * (1 << (Q)) + 0.5))
		 */
		public static int SKP_FIX_CONST( float C, int Q )
		{
			return (int)( C * ( 1 << Q ) + 0.5 );
		}

		/* SKP_min() versions with typecast in the function call */
		public static int SKP_min_int( int a, int b )
		{
			return ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) );
		}
		public static short SKP_min_16( short a, short b )
		{
			return ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) );
		}
		public static int SKP_min_32( int a, int b )
		{
			return ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) );
		}
		public static long SKP_min_64( long a, long b )
		{
			return ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) );
		}

		/* SKP_min() versions with typecast in the function call */
		public static int SKP_max_int( int a, int b )
		{
			return ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) );
		}
		public static short SKP_max_16( short a, short b )
		{
			return ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) );
		}
		public static int SKP_max_32( int a, int b )
		{
			return ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) );
		}
		public static long SKP_max_64( long a, long b )
		{
			return ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) );
		}

		public static int SKP_LIMIT( int a, int limit1, int limit2 )
		{
			if( limit1 > limit2 )
				return a > limit1 ? limit1 : ( a < limit2 ? limit2 : a );
			else
				return a > limit2 ? limit2 : ( a < limit1 ? limit1 : a );
		}
		public static float SKP_LIMIT( float a, float limit1, float limit2 )
		{
			if( limit1 > limit2 )
				return a > limit1 ? limit1 : ( a < limit2 ? limit2 : a );
			else
				return a > limit2 ? limit2 : ( a < limit1 ? limit1 : a );
		}

		public static int SKP_LIMIT_int( int a, int limit1, int limit2 )
		{
			if( limit1 > limit2 )
				return a > limit1 ? limit1 : ( a < limit2 ? limit2 : a );
			else
				return a > limit2 ? limit2 : ( a < limit1 ? limit1 : a );
		}
		public static short SKP_LIMIT_16( short a, short limit1, short limit2 )
		{
			if( limit1 > limit2 )
				return a > limit1 ? limit1 : ( a < limit2 ? limit2 : a );
			else
				return a > limit2 ? limit2 : ( a < limit1 ? limit1 : a );
		}
		public static int SKP_LIMIT_32( int a, int limit1, int limit2 )
		{
			if( limit1 > limit2 )
				return a > limit1 ? limit1 : ( a < limit2 ? limit2 : a );
			else
				return a > limit2 ? limit2 : ( a < limit1 ? limit1 : a );
		}


		/*
		 * (((a) >  0)  ? (a) : -(a))
		 * Be careful, SKP_abs returns wrong when input equals to SKP_intXX_MIN
		 * @param a
		 * @return
		 */
		public static int SKP_abs( int a )
		{
			return ( ( ( a ) > 0 ) ? ( a ) : -( a ) );
		}
		public static int SKP_abs_int( int a )
		{
			return ( ( ( a ) ^ ( ( a ) >> ( sizeof( int ) - 1 ) ) ) - ( ( a ) >> ( sizeof( int ) - 1 ) ) );
		}
		public static int SKP_abs_int32( int a )
		{
			return ( ( ( a ) ^ ( ( a ) >> 31 ) ) - ( ( a ) >> 31 ) );
		}
		public static long SKP_abs_int64( long a )
		{
			return ( ( ( a ) > 0 ) ? ( a ) : -( a ) );
		}

		public static int SKP_sign( int a )
		{
			return ( ( a ) > 0 ? 1 : ( ( a ) < 0 ? -1 : 0 ) );
		}

		public static double SKP_sqrt( int a )
		{
			return Math.Sqrt( a );
		}

		/*
		 * PSEUDO-RANDOM GENERATOR                                                          
		 * Make sure to store the result as the seed for the next call (also in between     
		 * frames), otherwise result won't be random at all. When only using some of the    
		 * bits, take the most significant bits by right-shifting. Do not just mask off     
		 * the lowest bits. 
		 * SKP_RAND(seed)                   (SKP_MLA_ovflw(907633515, (seed), 196314165))
		 * @param seed
		 * @return
		 */
		public static int SKP_RAND( int seed )
		{
			return 907633515 + seed * 196314165;
		}

		// Add some multiplication functions that can be easily mapped to ARM.

		//	   SKP_SMMUL: Signed top word multiply. 
		//	        ARMv6        2 instruction cycles. 
		//	        ARMv3M+        3 instruction cycles. use SMULL and ignore LSB registers.(except xM) 
		//  #define SKP_SMMUL(a32, b32)            (SKP_int32)SKP_RSHIFT(SKP_SMLAL(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)), 16)
		//     the following seems faster on x86
		//	#define SKP_SMMUL(a32, b32)              (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32)
		public static int SKP_SMMUL( int a32, int b32 )
		{
			return (int)( ( (long)a32 * b32 ) >> 32 );
		}
	}
}